package com.zzh.core.aop;

import com.zzh.core.global.ApiConstants;
import common.dto.CommonResponse;
import common.helper.LogHelper;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * Created by zhuxh on 16/5/10.
 */
@Aspect
//@Component
public class ApiControllerAspect {

  private final Logger apiLogger = LoggerFactory.getLogger("api");

  private final Logger logger = LoggerFactory.getLogger(this.getClass());

  @Pointcut(value = "execution(* com.zzh.core.controller.*.*(..))")
  public void apiMethods() {
  }

  @Around("apiMethods()")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    Long now = System.currentTimeMillis();
    // 接收到请求，记录请求内容
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes()).getRequest();
    String traceId = request.getHeader("traceId");
    if (StringUtils.isBlank(traceId)) {
      traceId = LogHelper.generateTraceId(now);
    }
    org.slf4j.MDC.put(ApiConstants.REQUEST_KEY, traceId);
    Object obj = null;
    try {
      obj = joinPoint.proceed();
    } catch (Exception ex) {
      throw ex;
    } finally {
      Long cost = System.currentTimeMillis() - now;
      if (obj instanceof CommonResponse) {
        ((CommonResponse) obj).setRequestId(traceId);
        ((CommonResponse) obj).setCost(cost);
      }
      String respJSONStr = String.valueOf(obj);
      String logStr = LogHelper
          .getLogWithRequestParam(request, respJSONStr,
              joinPoint.getSignature().getDeclaringTypeName(),
              joinPoint.getSignature().getName(), cost);
      apiLogger.info(logStr);
      org.slf4j.MDC.remove(ApiConstants.REQUEST_KEY);
    }
    return obj;
  }

  @AfterThrowing(pointcut = "apiMethods()", throwing = "e")
  public void afterThrowing(JoinPoint joinPoint, Throwable e) {
    logger.error("Exception in {}.{}() with cause = {}",
        joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(),
        e.getCause(), e);
  }
}
